#include "utils.h"
#include "scene.h"
#include "bass.h"
#include < algorithm >
#include < cctype >

#ifdef WIN32
	#include <windows.h>
#else
	#include <sys/time.h>
#endif

#include "includes.h"

long getTime()
{
	#ifdef WIN32
		//return GetTickCount();
		return timeGetTime();
		//return QueryPerformanceCounter();
	#else
		struct timeval tv;
		gettimeofday(&tv,NULL);
		return (int)(tv.tv_sec*1000 + (tv.tv_usec / 1000));
	#endif
}

//Draw the grid
void drawGrid(float dist)
{
	int num_lines = 20;
	glLineWidth(1);
	glColor3f(0.5,0.5,0.5);
	glBegin( GL_LINES );
		for (int i = 0; i <= num_lines * 0.5; ++i)
		{
			float a = dist * num_lines * 0.5;
			float b = i * dist;
			
			if (i == num_lines * 0.5)
				glColor3f(1,0.25,0.25);
			else if (i%2)
				glColor3f(0.25,0.25,0.25);
			else
				glColor3f(0.5,0.5,0.5);


			glVertex3f(a,b,-a);
			glVertex3f(-a,b,-a);
			glVertex3f(a,-b,-a);
			glVertex3f(-a,-b,-a);
			glVertex3f(b,a,-a);
			glVertex3f(b,-a,-a);
			glVertex3f(-b,a,-a);
			glVertex3f(-b,-a,-a);
			glVertex3f(a,b,a);
			glVertex3f(-a,b,a);
			glVertex3f(a,-b,a);
			glVertex3f(-a,-b,a);
			glVertex3f(b,a,a);
			glVertex3f(b,-a,a);
			glVertex3f(-b,a,a);
			glVertex3f(-b,-a,a);


			glVertex3f(a,-a,b);
			glVertex3f(-a,-a,b);
			glVertex3f(a,-a,-b);
			glVertex3f(-a,-a,-b);

			glVertex3f(b,-a,a);
			glVertex3f(b,-a,-a);
			glVertex3f(-b,-a,a);
			glVertex3f(-b,-a,-a);

			glVertex3f(-a, a,b);
			glVertex3f(-a, -a,b);
			glVertex3f(-a, a,-b);
			glVertex3f(-a, -a,-b);
			glVertex3f(-a, b,a);
			glVertex3f(-a, b,-a);
			glVertex3f(-a, -b,a);
			glVertex3f(-a, -b,-a);
			glVertex3f(a, a,b);
			glVertex3f(a, -a,b);
			glVertex3f(a, a,-b);
			glVertex3f(a, -a,-b);
			glVertex3f(a, b,a);
			glVertex3f(a, b,-a);
			glVertex3f(a, -b,a);
			glVertex3f(a, -b,-a);
		}
	glEnd();
}

float getDistance (Vector3 A, Vector3 B)
{
	return ( abs(A.x - B.x) +  abs(A.y - B.y) +  abs(A.z - B.z) );
}

bool isCloserThan(Vector3 A, Vector3 B, float distance)
{
	if (getDistance(A, B) < distance)
		return true;
	else
		return false;
}

Vector3 getFireLinePredictive(int attacker, Vector3 targetPos, Vector3 targetSpeed)
{

	Scene * scene = Scene::getScene();
	Ship * s = scene->getShipById(attacker);
	Vector3 myPos = s->model->getPosition();
	Vector3 targetFuturePos = targetPos + targetSpeed;
	Vector3  FireLine = targetFuturePos - myPos;
	
	return FireLine.normalize();
}

Vector3 getFireLine(int attacker, Vector3 targetPos)
{

	Scene * scene = Scene::getScene();
	Ship * s = scene->getShipById(attacker);
	Vector3 myPos = s->model->getPosition();
	Vector3  FireLine = targetPos - myPos;
	
	return FireLine.normalize();
}

bool isOnFireLine(int attacker, Vector3 FireLine, float accuracy)
{
	Scene * scene = Scene::getScene();
	Ship * s = scene->getShipById(attacker);

	Vector3 myPos = s->model->getPosition();
	Vector3 Front = s->model->frontVector();
	Vector3 myFront = Front - myPos;
	myFront.normalize();

	float fire = FireLine.dot(Front);
	
 	if (abs(fire) >= accuracy)
		return true;
	else
		return false;
}

void fireTarget(int attacker, Vector3 FireLine, int weapon)
{
	Scene * scene = Scene::getScene();
	Ship * s = scene->getShipById(attacker);
	Ship * player = scene->getShipPlayer();
	SoundManager * SM = SoundManager::getSoundManager();
	//Esto deberia de estar en la informacion de la instancia
	Vector3 leftMG = *s->model * Vector3(-8,0,-10);
	Vector3 rightMG = *s->model * Vector3(8,0,-10);
	Vector3 laserCA = *s->model * Vector3(0,0,-10);
	Vector3 plasmaCA = *s->model * Vector3(0,-4,0);
	///////////////////////////////////////////////////////////////////////////////////
	std::string action;
	action = "";
	unsigned long time = getTime();

	FireLine = FireLine * 3;

	//BASS_3DVECTOR bpos,borient,bvel;
	Vector3 pos,pos1,pos2, front, vel;
	pos1 = s->model->getPosition();
	pos2 = player->model->getPosition();
	front = s->model->frontVector();
	vel = s->velocidad;
	/*
	bpos.x = pos.x; 
	bpos.y = pos.y;
	bpos.z = pos.z;
	
	borient.x = front.x;
	borient.y = front.y;
	borient.z = -front.z;

	bvel.x = vel.x;
	bvel.y = vel.y;
	bvel.z = vel.z;
	*/
	vel = -front * 3;
	int i;
	switch(weapon) 
	{
		case 1:
			if(time - s->lastFire[0]> 50){
				s->lastFire[0] = time;
				scene->addProjectile(leftMG, vel, attacker, weapon);
				scene->addProjectile(rightMG, vel,  attacker, weapon);
				/*
				HSAMPLE sample = SM->getSampleID("laser_fire");
				if (sample != NULL){
					bool bass = BASS_ChannelSet3DPosition(HSAMPLE,&bpos,&porient,&bvel);
				}
				SM->playSound("laser_fire",1);
				*/
				double dist = getDistance(pos1,pos2);
				if(dist < 500.0)
 					SM->playSound("laser_fire",1);
			}
			break;
		case 2:
			if((time - s->lastFire[1]) > 1000){
				s->lastFire[1] = time;
				scene->addProjectile(laserCA, vel, attacker, weapon);
			}
			break;
		case 3:
			if((time - s->lastFire[2]) > 500){
				s->lastFire[2] = time;
 				scene->addProjectile(plasmaCA, vel,  attacker, weapon);
				
				/*Sample * sample = &SM->getSampleID("laser_fire");
				SM->setSamplerChannel("laser_fire", BASS_SampleGetChannel(sample->sample, false));
				i = BASS_ErrorGetCode();
				if(sample->channel == NULL){
					sample->channel = BASS_SampleGetChannel(sample->sample, false);
					i = BASS_ErrorGetCode();
				}
				if (sample->sample != NULL){
					//bool bass = BASS_ChannelSet3DAttributes(sample->channel,BASS_3DMODE_NORMAL,50,400.0,0,0,0);
					//BASS_Apply3D();
					//bass = BASS_ChannelSet3DPosition(sample->channel,&bpos,&borient,&bvel);
					//i = BASS_ErrorGetCode(); 
					//BASS_Apply3D(); 
					//i = BASS_ErrorGetCode();
				}
				*/
				double dist = getDistance(pos1,pos2);
				if(dist < 500.0)
 				SM->playSound("plasma_fire",1);
			}
			break;
	}
	if(BASS_ErrorGetCode() != 0) std::cout << "UTILS :: Error bass #" << BASS_ErrorGetCode() << std::endl;
	
}


void StringUtils::MakeUpper(std::string &str)
{
	std::transform(str.begin(),str.end(),str.begin(),toupper);
}

void StringUtils::MakeLower(std::string &str)
{
	std::transform(str.begin(),str.end(),str.begin(),tolower);
}

void StringUtils::TrimLeft(std::string& str, const char* chars2remove)
{
	if (!str.empty())
	{
		std::string::size_type pos = str.find_first_not_of(chars2remove);

		if (pos != std::string::npos)
			str.erase(0,pos);
		else
			str.erase( str.begin() , str.end() ); // make empty
	}
}

void StringUtils::TrimRight(std::string& str, const char* chars2remove)
{
	if (!str.empty())
	{
		std::string::size_type pos = str.find_last_not_of(chars2remove);

		if (pos != std::string::npos)
			str.erase(pos+1);
		else
			str.erase( str.begin() , str.end() ); // make empty
	}
}


void StringUtils::ReplaceLeading(std::string& str, const char* chars2replace, char c)
{
	if (!str.empty())
	{
		std::string::size_type pos = str.find_first_not_of(chars2replace);

		if (pos != std::string::npos)
			str.replace(0,pos,pos,c);
		else
		{
			int n = str.size();
			str.replace(str.begin(),str.end()-1,n-1,c);
		}
	}
}
